package com.teamwhole.modules.act.service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Attachment;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.teamwhole.common.utils.StringUtils;
import com.teamwhole.modules.act.dao.ActDao;
import com.teamwhole.modules.act.entity.Act;
import com.teamwhole.modules.act.utils.ProcessDefCache;
import com.teamwhole.modules.sys.entity.User;
import com.teamwhole.modules.sys.utils.UserUtils;

@Service
@Transactional(readOnly = true)
public class ActTaskService {
	
    @Autowired
    private ActDao actDao;
    
    @Autowired
    private ProcessEngineFactoryBean processEngine;
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    private FormService formService;
    
    @Autowired
    private HistoryService historyService;
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Autowired
    private IdentityService identityService;
    
    /**
     * 获取流程列表
     * @param category
     * @return
     */
    public List<Object[]> processList(String category) {
    	// 保存两个对象，一个是ProcessDefinition（流程定义），一个是Deployment（流程部署）
        ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery()
                .latestVersion()
                .active()
                .orderByProcessDefinitionKey()
                .asc();
        if (StringUtils.isNotEmpty(category)){
            pdq.processDefinitionCategory(category);
        }
        //pdq.count()
        //List<ProcessDefinition> processDefinitionList = pdq.listPage(page.getFirstResult(), page.getMaxResults());
        List<ProcessDefinition> processDefinitionList = pdq.list();
        List <Object[]> list = Lists.newArrayList();
        for (ProcessDefinition processDefinition : processDefinitionList) {
          String deploymentId = processDefinition.getDeploymentId();
          Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
          list.add(new Object[]{processDefinition, deployment});
        }
        return list;
    }
    
    /**
     * 获取待办列表
     * @param act
     * @return
     */
    @Transactional(readOnly = false)
    public List<Act> todoList(Act act, String userId) {
        //String userId = UserUtils.getUser().getLoginName();// UserUtils.getUser().getLoginName();//ObjectUtils.toString(UserUtils.getUser().getId());
        List<Act> result = new ArrayList<Act>();
        
        // =============== 已经签收的任务 ===============
        TaskQuery todoTaskQuery = taskService.createTaskQuery()
                .taskAssignee(userId)
                .active()
                .includeProcessVariables()
                .orderByTaskCreateTime()
                .desc();
        // 设置查询条件
        if (StringUtils.isNotBlank(act.getProcDefKey())) {
            todoTaskQuery.processDefinitionKey(act.getProcDefKey());
        }
        if (act.getBeginDate() != null) {
            todoTaskQuery.taskCreatedAfter(act.getBeginDate());
        }
        if (act.getEndDate() != null) {
            todoTaskQuery.taskCreatedBefore(act.getEndDate());
        }
        // 查询列表
        List<Task> todoList = todoTaskQuery.list();
        for (Task task : todoList) {
            Act e = new Act();
            e.setTask(task);
            e.setVars(task.getProcessVariables());
            // e.setTaskVars(task.getTaskLocalVariables());
            // System.out.println(task.getId()+" = "+task.getProcessVariables() + " ========== " + task.getTaskLocalVariables());
            e.setProcDef(ProcessDefCache.get(task.getProcessDefinitionId()));
            // e.setProcIns(runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult());
            // e.setProcExecUrl(ActUtils.getProcExeUrl(task.getProcessDefinitionId()));
            e.setStatus("todo");
            result.add(e);
        }

        // =============== 待签收的任务 ===============
        TaskQuery toClaimQuery = taskService.createTaskQuery()
                .taskCandidateUser(userId)
                .includeProcessVariables()
                .active()
                .orderByTaskCreateTime()
                .desc();
        // 设置查询条件
        if (StringUtils.isNotBlank(act.getProcDefKey())) {
            toClaimQuery.processDefinitionKey(act.getProcDefKey());
        }
        if (act.getBeginDate() != null) {
            toClaimQuery.taskCreatedAfter(act.getBeginDate());
        }
        if (act.getEndDate() != null) {
            toClaimQuery.taskCreatedBefore(act.getEndDate());
        }
        // 查询列表
        List<Task> toClaimList = toClaimQuery.list();
        for (Task task : toClaimList) {
            Act e = new Act();
            e.setTask(task);
            e.setVars(task.getProcessVariables());
            // e.setTaskVars(task.getTaskLocalVariables());
            // System.out.println(task.getId()+" = "+task.getProcessVariables() + " ========== " +
            // task.getTaskLocalVariables());
            e.setProcDef(ProcessDefCache.get(task.getProcessDefinitionId()));
            // e.setProcIns(runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult());
            // e.setProcExecUrl(ActUtils.getProcExeUrl(task.getProcessDefinitionId()));
            e.setStatus("claim");
            result.add(e);
        }
        return result;
    }
    
    /**
     * 获取已办任务(我参与的流程)
     * @param act
     * @return
     */
    public Map<String, Object> historicList(Act act, String userId) {
        //String userId = UserUtils.getUser().getLoginName();
        HistoricTaskInstanceQuery histTaskQuery = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId)
                .finished()
                .includeProcessVariables()
                .orderByHistoricTaskInstanceEndTime()
                .desc();
        // 设置查询条件
        if (StringUtils.isNotBlank(act.getProcDefKey())) {
            histTaskQuery.processDefinitionKey(act.getProcDefKey());
        }
        if (act.getBeginDate() != null) {
            histTaskQuery.taskCompletedAfter(act.getBeginDate());
        }
        if (act.getEndDate() != null) {
            histTaskQuery.taskCompletedBefore(act.getEndDate());
        }
        
        Map<String, Object> map = Maps.newHashMap();
        // 查询总数
        // page.setCount(histTaskQuery.count());
        // 查询列表
        List<HistoricTaskInstance> histList = histTaskQuery.listPage(act.getPage(), act.getRows());
        // 处理分页问题
        List<Act> actList = Lists.newArrayList();
        for (HistoricTaskInstance histTask : histList) {
            Act e = new Act();
            e.setHistTask(histTask);
            e.setVars(histTask.getProcessVariables());
            // e.setTaskVars(histTask.getTaskLocalVariables());
            // System.out.println(histTask.getId()+" = "+histTask.getProcessVariables() + "========== " + histTask.getTaskLocalVariables());
            e.setProcDef(ProcessDefCache.get(histTask.getProcessDefinitionId()));
            // e.setProcIns(runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult());
            // e.setProcExecUrl(ActUtils.getProcExeUrl(task.getProcessDefinitionId()));
            //TODO
            //e.setStatus("finish");
            actList.add(e);
        }
        map.put("rows", actList);
        map.put("total", histTaskQuery.count());
        return map;
    }
    
    /**
     * 获取流转历史列表
     * @param procInsId
     * @param startAct
     * @param endAct
     * @return
     */
    public List<Act> histoicFlowList(String procInsId, String startAct, String endAct) {
        List<Act> actList = Lists.newArrayList();
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId)
                .orderByHistoricActivityInstanceStartTime().asc()
                .orderByHistoricActivityInstanceEndTime().asc()
                .list();
        boolean start = false;
        Map<String, Integer> actMap = Maps.newHashMap();
        for (int i=0; i<list.size(); i++){
            HistoricActivityInstance histIns = list.get(i);
            // 过滤开始节点前的节点
            if (StringUtils.isNotBlank(startAct) && startAct.equals(histIns.getActivityId())){
                start = true;
            }
            if (StringUtils.isNotBlank(startAct) && !start){
                continue;
            }
            // 只显示开始节点和结束节点，并且执行人不为空的任务
            if (StringUtils.isNotBlank(histIns.getAssignee()) || "startEvent".equals(histIns.getActivityType()) || "endEvent".equals(histIns.getActivityType())){
                // 给节点增加一个序号
                Integer actNum = actMap.get(histIns.getActivityId());
                if (actNum == null){
                    actMap.put(histIns.getActivityId(), actMap.size());
                }
                Act e = new Act();
                e.setHistIns(histIns);
                // 获取流程发起人名称
                if ("startEvent".equals(histIns.getActivityType())){
                    List<HistoricProcessInstance> il = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).orderByProcessInstanceStartTime().asc().list();
                    //List<HistoricIdentityLink> il = historyService.getHistoricIdentityLinksForProcessInstance(procInsId);
                    if (il.size() > 0){
                        if (StringUtils.isNotBlank(il.get(0).getStartUserId())){
                            User user = UserUtils.findByLoginName(il.get(0).getStartUserId());
                            if (user != null){
                                e.setAssignee(histIns.getAssignee());
                                e.setAssigneeName(user.getName());
                            }
                        }
                    }
                }
                // 获取任务执行人名称
                if (StringUtils.isNotEmpty(histIns.getAssignee())){
                    User user = UserUtils.findByLoginName(histIns.getAssignee());
                    if (user != null){
                        e.setAssignee(histIns.getAssignee());
                        e.setAssigneeName(user.getName());
                    }
                }
                
                // 获取意见评论内容
                if (StringUtils.isNotBlank(histIns.getTaskId())){
                    List<Comment> commentList = taskService.getTaskComments(histIns.getTaskId());
                    if (commentList.size() > 0){
                        e.setComment(commentList.get(0).getFullMessage());
                    }
                }
                // 获取附件列表
                if (StringUtils.isNotBlank(histIns.getTaskId())){
                	List<Attachment> attachments = taskService.getTaskAttachments(histIns.getTaskId());
                	if (attachments.size() > 0) {
                		e.setAttachments(attachments);
                	}
                }
                actList.add(e);
            }
            // 过滤结束节点后的节点
            if (StringUtils.isNotBlank(endAct) && endAct.equals(histIns.getActivityId())){
                boolean bl = false;
                Integer actNum = actMap.get(histIns.getActivityId());
                // 该活动节点，后续节点是否在结束节点之前，在后续节点中是否存在
                for (int j=i+1; j<list.size(); j++){
                    HistoricActivityInstance hi = list.get(j);
                    Integer actNumA = actMap.get(hi.getActivityId());
                    if ((actNumA != null && actNumA < actNum) || StringUtils.equals(hi.getActivityId(), histIns.getActivityId())){
                        bl = true;
                    }
                }
                if (!bl){
                    break;
                }
            }
        }
        return actList;
    }
    
    /**
     * 获取流程表单（首先获取任务节点表单KEY，如果没有则取流程开始节点表单KEY）
     * @param procDefId
     * @param taskDefKey
     * @return
     */
    public String getFormKey(String procDefId, String taskDefKey) {
        String formKey = "";
        if (StringUtils.isNotBlank(procDefId)) {
            if (StringUtils.isNotBlank(taskDefKey)) {
                try {
                    formKey = formService.getTaskFormKey(procDefId, taskDefKey);
                } catch (Exception e) {
                    formKey = "";
                }
            }
            if (StringUtils.isBlank(formKey)) {
                formKey = formService.getStartFormKey(procDefId);
            }
            if (StringUtils.isBlank(formKey)) {
                formKey = "/404";
            }
        }
        return formKey;
    }
    
    /**
     * 读取带跟踪的图片
     * @param executionId   环节ID
     * @return  封装了各种节点信息
     */
    public InputStream tracePhoto(String processDefinitionId, String executionId) {
        // ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(executionId).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        
        List<String> activeActivityIds = Lists.newArrayList();
        if (runtimeService.createExecutionQuery().executionId(executionId).count() > 0){
            activeActivityIds = runtimeService.getActiveActivityIds(executionId);
        }
        // 不使用spring请使用下面的两行代码
        // ProcessEngineImpl defaultProcessEngine = (ProcessEngineImpl)ProcessEngines.getDefaultProcessEngine();
        // Context.setProcessEngineConfiguration(defaultProcessEngine.getProcessEngineConfiguration());
        
        // 使用spring注入引擎请使用下面的这行代码
        Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
        return ProcessDiagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds);
    }
    
    /**
     * 获取流程实例对象
     * @param procInsId
     * @return
     */
    public ProcessInstance getProcIns(String procInsId) {
        return runtimeService.createProcessInstanceQuery().processInstanceId(procInsId).singleResult();
    }
    
    /**
     * 启动流程
     * @param procDefKey 流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @return 流程实例ID
     */
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId) {
        return startProcess(procDefKey, businessTable, businessId, "");
    }
    
    /**
     * 启动流程
     * @param procDefKey 	流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @param title         流程标题,显示在待办任务标题
     * @return 流程实例ID
     */
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId, String title) {
        //Map<String, Object> vars = Maps.newHashMap();
        return startProcess(procDefKey, businessTable, businessId, title, null, null);
    }
    
    /**
     * 启动流程
     * @param procDefKey 	流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @param title         流程标题,显示在待办任务标题
     * @param vars          流程变量
     * @return 流程实例ID
     */
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId, String title, Map<String, Object> vars, String userId) {
        //String userId = UserUtils.getUser().getLoginName();
        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(userId);
        // 设置流程变量
        if (vars == null){
            vars = Maps.newHashMap();
        }
        // 设置流程标题
        if (StringUtils.isNotBlank(title)){
            vars.put("title", title);
        }
        // 启动流程
        ProcessInstance procIns = runtimeService.startProcessInstanceByKey(procDefKey, (businessTable + ":" + businessId), vars);
        // 更新业务表流程实例ID
        Act act = new Act();
        act.setBusinessTable(businessTable);// 业务表名
        act.setBusinessId(businessId);      // 业务表ID
        act.setProcInsId(procIns.getId());
        actDao.updateProcInsIdByBusinessId(act);
        return act.getProcInsId();
    }
    
    /**
     * 获取任务
     * @param taskId 任务ID
     */
    public Task getTask(String taskId){
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }
    
    /**
     * 获取任务
     * @param taskId 任务ID
     */
    public Task getTaskIncludeVars(String taskId){
        return taskService.createTaskQuery().includeProcessVariables().taskId(taskId).singleResult();
    }
    
    /**
     * 签收任务
     * @param taskId 任务ID
     * @param userId 签收用户ID（用户登录名）
     */
    @Transactional(readOnly = false)
    public void claim(String taskId, String userId){
        taskService.claim(taskId, userId);
    }
    
    /**
     * 删除任务
     * @param taskId 任务ID
     * @param deleteReason 删除原因
     */
    @Transactional(readOnly = false)
    public void deleteTask(String taskId, String deleteReason){
        taskService.deleteTask(taskId, deleteReason);
    }
    
    /**
     * 提交任务, 并保存意见
     * @param taskId 任务ID
     * @param procInsId 流程实例ID，如果为空，则不保存任务提交意见
     * @param comment 任务提交意见的内容
     * @param vars 任务变量
     */
    @Transactional(readOnly = false)
    public void complete(String taskId, String procInsId, String comment, Map<String, Object> vars){
        complete(taskId, procInsId, comment, "", vars);
    }
    
    /**
     * 提交任务, 并保存意见
     * @param taskId 任务ID
     * @param procInsId 流程实例ID，如果为空，则不保存任务提交意见
     * @param comment 任务提交意见的内容
     * @param title         流程标题，显示在待办任务标题
     * @param vars 任务变量
     */
    @SuppressWarnings("unchecked")
	@Transactional(readOnly = false)
    public void complete(String taskId, String procInsId, String comment, String title, Map<String, Object> vars){
        // 添加意见
        if (StringUtils.isNotBlank(procInsId) && StringUtils.isNotBlank(comment)){
            taskService.addComment(taskId, procInsId, comment);
        }
        // 设置流程变量
        if (vars == null){
            vars = Maps.newHashMap();
        }
        // 设置流程标题
        if (StringUtils.isNotBlank(title)){
            vars.put("title", title);
        }
        
        // 附件设置
        if (vars.get("attachments") != null) {
        	List<Map<String,String>> list = (List<Map<String, String>>) vars.get("attachments");
        	for(Map<String,String> item : list){
        		taskService.createAttachment(item.get("attachmentType"), taskId, procInsId, item.get("attachmentName"), item.get("attachmentDescription"), item.get("url"));
        	}
        }
        
        // 提交任务
        taskService.complete(taskId, vars);
    }
    

//  /**
//   * 委派任务
//   * @param taskId 任务ID
//   * @param userId 被委派人
//   */
//  public void delegateTask(String taskId, String userId){
//      taskService.delegateTask(taskId, userId);
//  }
//  
//  /**
//   * 被委派人完成任务
//   * @param taskId 任务ID
//   */
//  public void resolveTask(String taskId){
//      taskService.resolveTask(taskId);
//  }
//  
//  /**
//   * 回退任务
//   * @param taskId
//   */
//  public void backTask(String taskId){
//      taskService.
//  }
    
}
